#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include "network.h"
#include "counter.h"
#include "common.h"
#include "mutex.h"

#define PROCESS_COUNT 10

int client_socket_id = -1;
int accept_mutex;
struct counter_t counter;


void recieve_request(int server_socket_id, int process_id) 
{
  socklen_t socket_length = sizeof(struct sockaddr_in);
  struct sockaddr_in client_adress;
  while (1) {
    mutex_lock(accept_mutex);
    client_socket_id = accept(server_socket_id, (struct sockaddr *) &client_adress, &socket_length);
    mutex_unlock(accept_mutex);
    error_if(client_socket_id < 0, "Unanable to accept");
    printf("Process %d get request from %s\n", process_id, inet_ntoa(client_adress.sin_addr));
    int data = htonl(counter_increment(counter));
    int result = write(client_socket_id, &data, sizeof(data));
    error_if(result != sizeof(data), "Error in writing");
    error_if(close(client_socket_id) == -1, "Error in closing");
    client_socket_id = -1;
  }
}

void child_sigint(int no)
{
  counter_deattach(counter);
  exit(0);
}

void parent_sigint(int no)
{
  //do nothing, program will exit when last child will exit
  signal(SIGINT, parent_sigint);
}


void spawn_children(int server_socket_id) 
{
  int i;
  for (i = 0; i < PROCESS_COUNT; i++) {
    int result = fork();
    error_if(result < 0, "Unanable to spawn enough processes");
    if (result == 0) {
      signal(SIGINT, child_sigint);
      recieve_request(server_socket_id, i+1);
    }
  }
}

void wait_for_children()
{
  int i;
  for (i = 0; i < PROCESS_COUNT; i++) 
    error_if(waitpid(0, NULL, 0) == -1, "Unanable to wait");
}

int main() 
{
   
  int server_socket_id = server_socket_open(PORT);
  int listen_result = listen(server_socket_id,5);
  error_if(listen_result < 0, "Unanable to listen");  

  counter = counter_create();
  accept_mutex = unsafe_mutex_create();
  if (accept_mutex == -1) {
    counter_destroy(counter);
    exit(1);
  }

  spawn_children(server_socket_id);

  signal(SIGINT, parent_sigint);

  wait_for_children();

  /* clean up */
  close(server_socket_id);
  counter_deattach(counter);
  counter_destroy(counter);
  mutex_destroy(accept_mutex);
  return 0;
}
